/*
 *  Netzpult - Your desk on the web
 *  Copyright (C) 2011  Ulrich Hilger, http://uhilger.de
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/
 */

package de.uhilger.netzpult.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.security.Principal;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;

import de.uhilger.netzpult.server.db.DataStorage;
import de.uhilger.netzpult.server.db.DataStorageImpl;
import de.uhilger.netzpult.shared.Document;

/**
 * 
 * @author Copyright (c) Ulrich Hilger, http://uhilger.de
 * @author Published under the terms and conditions of
 * the <a href="http://www.gnu.org/licenses/" target="_blank">GNU General Public License</a>
 */
public class UploadServlet extends HttpServlet {

	private static final long serialVersionUID = -3757231619672237999L;

	protected DataStorage ds;
	//protected String userName;
	protected String mode;
	protected String dbtype;

	private void processRequest(HttpServletRequest request,
			HttpServletResponse response) throws ServletException {
		// Check that we have a file upload request
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		if (isMultipart) {
			try {
				parseMultipartRequest(request);
				Writer w = response.getWriter();
				w.write("<html><head><title>Upload done</title></head><body><p>Upload successful.</p></body></html>");
				w.flush();
			} catch (Exception e) {
				Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.getMessage(), e);
				throw new ServletException(e);
			}
		} else {
			// kein File Upload
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).severe("Not a file upload");
			throw new ServletException("Not a file upload.");
		}
	}

	private void parseMultipartRequest(HttpServletRequest request)
			throws Exception {
		// Create a new file upload handler
		ServletFileUpload upload = new ServletFileUpload();
		// Parse the request
		FileItemIterator iter = upload.getItemIterator(request);
		int len = 0;
		String type = null;
		int updateId = -1;
		while (iter.hasNext()) {
			FileItemStream item = iter.next();
			String itemType = item.getContentType();
			if(itemType != null) {
				type = itemType;
			}
			String name = item.getFieldName();
			InputStream stream = item.openStream();
			if (item.isFormField()) {
				String formFieldValue = Streams.asString(stream); 
				Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest("Form field " + name + " with value "
						+ formFieldValue + " detected.");
				if(name.equalsIgnoreCase("textBoxFormElement_length")) {
					try {
						len = Integer.parseInt(formFieldValue);
					} catch(Exception e) {}
				} else if(name.equalsIgnoreCase("listBoxFormElement_type")) {
					if(type == null) {
						type = formFieldValue;
					}
				} else if(name.equalsIgnoreCase("textBoxFormElement_updateDocId")) {
					updateId = Integer.parseInt(formFieldValue);
				}
			} else {
				Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest("File field " + name + " with file name "
						+ item.getName() + " detected.");
				// Process the input stream
				processInputStream(stream, item.getName(), getUserName(request), len, type, updateId);
			}
		}
	}

	private void processInputStream(InputStream stream, String name, String owner, int len, String type, int updateId) throws Exception {
		Document document = new Document();
		document.setMimeType(type);
		document.setTitle(name);
		if(updateId < 0) {
			ds.createDocument(document, owner, stream, len);
		} else {
			document.setId(updateId);
			ds.createNewVersion(document, owner, stream, len);
		}
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		processRequest(req, resp);
	}

	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		processRequest(req, resp);
	}

	protected void doPut(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		processRequest(req, resp);
	}

	private String getUserName(HttpServletRequest req) {
		String userName = null;
		Principal p = req.getUserPrincipal();
		if(p != null) {
			userName = p.getName();
		}
		if(userName == null) {
			userName = AbstractWebfilesServlet.ANONYMOUS_OWNER;
		}
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest(userName);
		return userName;
	}

	public void init(ServletConfig config) throws ServletException {
		
		ServletContext context = config.getServletContext();

		mode = context.getInitParameter(AbstractWebfilesServlet.MODE);
		String dbtype = context.getInitParameter(AbstractWebfilesServlet.DB_TYPE);
		String dburl = context.getInitParameter(AbstractWebfilesServlet.DB_URL);
		
		Level loglevel = Level.FINEST;
		if(config != null) {
			String logLevelStr = context.getInitParameter(AbstractWebfilesServlet.LOGLEVEL);
			if(logLevelStr != null) {
				loglevel = Level.parse(logLevelStr.toUpperCase());
			}
		}
		
		Object o = context.getAttribute(DataStorage.NAME);
		if (o == null) {
			//System.out.println(new Date() + " UploadServlet.init creating DatabaseAdapter");
			ds = new DataStorageImpl(mode, dbtype, dburl);
			context.setAttribute(DataStorage.NAME, ds);
		} else {
			ds = (DataStorage) o;
		}
		Logger globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
		Handler[] handlers = globalLogger.getHandlers();
		if(handlers.length == 0) {
			Handler handler = new ConsoleHandler();
			handler.setLevel(loglevel);
			globalLogger.addHandler(handler);
			globalLogger.setLevel(loglevel);
		}
		super.init(config);
	}
}
